!> \file GFS_time_vary_pre.fv3.F90
!!  Contains code related to GFS physics suite setup (generic part of time_vary_step)

   module GFS_time_vary_pre

      use funcphys, only: gfuncphys

      implicit none

      private

      public GFS_time_vary_pre_init, GFS_time_vary_pre_timestep_init, GFS_time_vary_pre_finalize

      logical :: is_initialized = .false.

      contains

!>\defgroup gfs_time_vary_pre_mod  GFS Time Vary Pre Module
!! This module contains code related to GFS physics suite setup.
!> @{
!> \section arg_table_GFS_time_vary_pre_init Argument Table
!! \htmlinclude GFS_time_vary_pre_init.html
!!
      subroutine GFS_time_vary_pre_init (errmsg, errflg)

         implicit none

         character(len=*),                 intent(out)   :: errmsg
         integer,                          intent(out)   :: errflg

         ! Initialize CCPP error handling variables
         errmsg = ''
         errflg = 0

         if (is_initialized) return

         !--- Call gfuncphys (funcphys.f) to compute all physics function tables.
         call gfuncphys ()

         is_initialized = .true.

      end subroutine GFS_time_vary_pre_init


!> \section arg_table_GFS_time_vary_pre_finalize Argument Table
!! \htmlinclude GFS_time_vary_pre_finalize.html
!!
      subroutine GFS_time_vary_pre_finalize(errmsg, errflg)

         implicit none

         character(len=*),                 intent(out)   :: errmsg
         integer,                          intent(out)   :: errflg

         ! Initialize CCPP error handling variables
         errmsg = ''
         errflg = 0

         if (.not. is_initialized) return

         ! DH* this is the place to deallocate whatever is allocated by gfuncphys() in GFS_time_vary_pre_init

         is_initialized = .false.

      end subroutine GFS_time_vary_pre_finalize


!> \section arg_table_GFS_time_vary_pre_timestep_init Argument Table
!! \htmlinclude GFS_time_vary_pre_timestep_init.html
!!
      subroutine GFS_time_vary_pre_timestep_init (jdat, idat, dtp, nsswr,                        &
                  nslwr, nhfrad, idate, debug, me, master, nscyc, sec, phour, zhour, fhour,      &
                  kdt, julian, yearlen, ipt, lprnt, lssav, lsswr, lslwr, solhr, errmsg, errflg)

        use machine,               only: kind_phys, kind_dbl_prec, kind_sngl_prec

        implicit none

        integer,                          intent(in)    :: idate(:)
        integer,                          intent(in)    :: jdat(:), idat(:)
        integer,                          intent(in)    :: nsswr, nslwr, me,     &
                                                           master, nscyc, nhfrad
        logical,                          intent(in)    :: debug
        real(kind=kind_phys),             intent(in)    :: dtp

        integer,                          intent(out)   :: kdt, yearlen, ipt
        logical,                          intent(out)   :: lprnt, lssav, lsswr,  &
                                                           lslwr
        real(kind=kind_phys),             intent(out)   :: sec, phour, zhour,    &
                                                           fhour, julian, solhr

        character(len=*),                 intent(out)   :: errmsg
        integer,                          intent(out)   :: errflg

        real(kind=kind_phys), parameter :: con_24  =   24.0_kind_phys
        real(kind=kind_phys), parameter :: con_hr  = 3600.0_kind_phys
        real(kind=kind_sngl_prec) :: rinc4(5)
        real(kind=kind_dbl_prec)  :: rinc8(5)

        integer :: w3kindreal,w3kindint
        integer ::  iw3jdn
        integer :: jd0, jd1
        real    :: fjd

        ! Initialize CCPP error handling variables
        errmsg = ''
        errflg = 0

        ! Check initialization status
        if (.not.is_initialized) then
           write(errmsg,'(*(a))') "Logic error: GFS_time_vary_pre_timestep_init called before GFS_time_vary_pre_init"
           errflg = 1
           return
        end if

        !--- jdat is being updated directly inside of FV3GFS_cap.F90
        !--- update calendars and triggers
        call w3kind(w3kindreal,w3kindint)
        if (w3kindreal == 8) then
           rinc8(1:5) = 0
           call w3difdat(jdat,idat,4,rinc8)
           sec = rinc8(4)
        else if (w3kindreal == 4) then
           rinc4(1:5) = 0
           call w3difdat(jdat,idat,4,rinc4)
           sec = rinc4(4)
        else
           write(0,*)' FATAL ERROR: Invalid w3kindreal'
           call abort
        endif
        phour = sec/con_hr
        !--- set current bucket hour
        zhour = phour
        fhour = (sec + dtp)/con_hr
        kdt   = nint((sec + dtp)/dtp)

        !GJF* These calculations were originally in GFS_physics_driver.F90 for
        !     NoahMP. They were moved to this routine since they only depend
        !     on time (not space). Note that this code is included as-is from
        !     GFS_physics_driver.F90, but it may be simplified by using more
        !     NCEP W3 library calls (e.g., see W3DOXDAT, W3FS13 for Julian day
        !     of year and W3DIFDAT to determine the integer number of days in
        !     a given year). *GJF
        ! Julian day calculation (fcst day of the year)
        ! we need yearln and julian to
        ! pass to noah mp sflx, idate is init, jdat is fcst;idate = jdat when kdt=1
        ! jdat is changing
        !

        jd1    = iw3jdn(jdat(1),jdat(2),jdat(3))
        jd0    = iw3jdn(jdat(1),1,1)
        fjd    = float(jdat(5))/24.0 + float(jdat(6))/1440.0

        julian = float(jd1-jd0) + fjd

        !
        ! Year length
        !
        ! what if the integration goes from one year to another?
        ! iyr or jyr ? from 365 to 366 or from 366 to 365
        !
        ! is this against model's noleap yr assumption?
        if (mod(jdat(1),4) == 0) then
          yearlen = 366
          if (mod(jdat(1),100) == 0) then
            yearlen = 365
            if (mod(jdat(1),400) == 0) then
              yearlen = 366
            endif
          endif
        endif

        ipt    = 1
        lprnt  = .false.
        lssav  = .true.

        !--- radiation triggers
        lsswr  = (mod(kdt, nsswr) == 1)
        lslwr  = (mod(kdt, nslwr) == 1)
        !--- allow for radiation to be called on every physics time step, if needed
        if (nsswr == 1)  lsswr = .true.
        if (nslwr == 1)  lslwr = .true.
        !--- allow for radiation to be called on every physics time step
        !    for the first nhfrad timesteps (for spinup, coldstarts only)
        if (kdt <= nhfrad) then
           lsswr = .true.
           lslwr = .true.
        end if

        !--- set the solar hour based on a combination of phour and time initial hour
        solhr  = mod(phour+idate(1),con_24)

        if ((debug) .and. (me == master)) then
          print *,'   sec ', sec
          print *,'   kdt ', kdt
          print *,' nsswr ', nsswr
          print *,' nslwr ', nslwr
          print *,' nscyc ', nscyc
          print *,' lsswr ', lsswr
          print *,' lslwr ', lslwr
          print *,' fhour ', fhour
          print *,' phour ', phour
          print *,' solhr ', solhr
        endif

      end subroutine GFS_time_vary_pre_timestep_init
!> @}
    end module GFS_time_vary_pre
